﻿
using System;
using System.Linq;


namespace BoilenEditor.Primitives {

    internal static class InsertBehavior {

        private static readonly string TabbedDeclaration = Ex.TabString + '.';


        public static void Insert( BindableTextEditor editor, string text ) {
            if( editor.SelectionLength == 0 ) {
                int insertLine = GetInsertLine( editor );
                int index = editor.GetCharacterIndexFromLineIndex( insertLine );

                editor.SelectionStart = index;
            }

            editor.SelectedText = text;
            editor.SelectionLength = 0;
            editor.SelectionStart += text.Length;

            int lineIndex = editor.GetLineIndexFromCharacterIndex( editor.SelectionStart );
            editor.ScrollToLine( lineIndex );
        }


        private static bool IsDeclarationPosition( BindableTextEditor editor, int lineIndex ) {
            string line = editor.GetLineText( lineIndex );
            return line.StartsWith( TabbedDeclaration );
        }

        private static bool IsAfterPartial( BindableTextEditor editor, int lineIndex ) {
            if( lineIndex <= 0 )
                return false;

            string previousLine = editor.GetLineText( lineIndex - 1 );
            return previousLine.StartsWith( "Partial" );
        }


        private static int? FindInsertLine( BindableTextEditor editor, Func<BindableTextEditor, int, bool> canInsert, int start, int end ) {
            int count = end - start;
            var insertLines = Enumerable.Range( start, count )
                .Where( lineIndex => canInsert( editor, lineIndex ) )
                .Select( lineIndex => (int?)lineIndex );

            return insertLines.FirstOrDefault( );
        }

        private static int? FindInsertLine( BindableTextEditor editor, Func<BindableTextEditor, int, bool> canInsert ) {
            return FindInsertLine( editor, canInsert, 0, editor.LineCount );
        }

        private static int GetInsertLine( BindableTextEditor editor ) {
            int currentLineIndex = editor.GetLineIndexFromCharacterIndex( editor.SelectionStart );
            return FindInsertLine( editor, IsDeclarationPosition, currentLineIndex, editor.LineCount )
                ?? FindInsertLine( editor, IsDeclarationPosition, 0, currentLineIndex )
                ?? FindInsertLine( editor, IsAfterPartial )
                ?? currentLineIndex;
        }

    }

}
